마라톤 사진 조회 시스템 아키텍처(임시)

업로드 / OCR 파이프라인 (행사 후)

%%{init: {"theme": "dark"}}%%
flowchart TD
    A[사진기사 촬영] --> B[행사 종료 후
원본 사진 업로드
20MB × n장] B --> C[로컬 OCR 배치 스크립트
Google Vision API] C --> D{배번표 인식} D -->|성공| E[Supabase
번호 ↔ 사진 URL 매핑 저장] D -->|실패/미인식| F[수동 처리] B --> G[Cloudflare R2
원본 이미지 저장] E --> H[준비 완료] G --> H

참가자 조회 플로우 (행사 당일 / 이후)

%%{init: {"theme": "dark"}}%%
flowchart TD
    A[참가자] --> B[번호 입력
웹사이트] B --> C[Vercel API
번호로 Supabase 조회] C --> D[매핑된 사진 URL 목록 반환] D --> E[R2 Presigned URL 생성
시간 제한 있음] E --> F[참가자에게 URL 전달] F --> G{원하는 작업} G -->|사진 다운로드| H[R2에서 직접 다운로드] G -->|인증서 발급| I[클라이언트에서
Canvas로 조합] I --> J[JPG / PNG 다운로드]

전체 인프라 구성

%%{init: {"theme": "dark"}}%%
flowchart LR
    subgraph Local
        A[OCR 배치 스크립트]
    end

    subgraph Cloudflare
        B[R2
이미지 저장
egress 무료] end subgraph Supabase C[PostgreSQL
번호 ↔ URL 매핑
Free Tier] end subgraph Vercel D[Next.js
프론트 + API] end A -->|사진 업로드| B A -->|매핑 저장| C D -->|번호 조회| C D -->|Presigned URL 생성| B B -->|이미지 전송| E[참가자] D --> E

비용 추정

항목 500명 기준 3000명 기준
R2 저장 (50GB / 300GB) ~$0.75/월 ~$4.5/월
R2 Egress 무료 무료
Supabase 무료 (Free Tier) 무료 (Free Tier)
Vercel 무료 (Free Tier) 무료 (Free Tier)
Google Vision OCR ~$3.75 (1회) ~$20 (1회)

구성 설명

업로드 / OCR 파이프라인

행사가 끝난 후 사진기사가 촬영한 원본 사진을 업로드한다. 업로드된 사진은 로컬에서 OCR 배치 스크립트를 돌려 배번표 번호를 인식하고, 번호와 사진 URL을 Supabase에 매핑해서 저장한다. OCR 처리는 실시간이 아니라 행사 후 한 번만 돌리면 되기 때문에 서버 타임아웃 걱정 없이 로컬에서 처리하는 게 깔끔하다.

참가자 조회 플로우

참가자가 웹사이트에서 배번표 번호를 입력하면 Vercel API가 Supabase에서 해당 번호에 매핑된 사진 URL을 조회한다. 이때 R2의 원본 URL을 직접 노출하지 않고 Presigned URL을 생성해서 전달한다. Presigned URL은 유효시간이 있어서 번호를 모르는 사람이 URL만으로 접근하는 걸 막을 수 있다. 사진 다운로드 외에 인증서 발급도 지원하며, 인증서는 서버에 저장하지 않고 클라이언트에서 Canvas로 조합해 JPG/PNG로 바로 다운로드하는 방식이라 별도 저장 비용이 없다.

인프라 구성